﻿using UnityEngine;
using UnityEngine.UI;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System;
using System.Extension;
using System.Reflection;

public enum CommandType
{
    Invoke, Navigate, ConditionalNavigate
}

[Serializable]
public class Command
{
    public UnityEngine.Object source;
    public UnityEngine.Object destination;
    public string methodPath;
    public CommandType type;
    public List<Parameter> parameters;

    public void LinkMethod(ControlBehaviour controlBehaviour)
    {
        switch (type)
        {
            case CommandType.Invoke:
                if (source is GameObject) LinkButton();
                break;
            case CommandType.ConditionalNavigate:
                if(destination is GameObject)  CheckForNavigation(controlBehaviour);
                break;
            case CommandType.Navigate:
                if (source is GameObject) LinkNavigation(controlBehaviour);
                break;
        }
    }

    private void CheckForNavigation(ControlBehaviour controlBehaviour)
    {
        ControlBehaviour destinationControl = (destination as GameObject).GetComponent<ControlBehaviour>();
        bool value = (bool)source.GetValue(methodPath);
        if (value)
        {
           // Debug.LogWarning("Naviation To : " + destinationControl.name + " from :" + controlBehaviour.name + " for Path :" + methodPath);
            controlBehaviour.NavigateTo(destinationControl);
        }
    }

    public void Clear()
    {
        if (source is GameObject)
        {
            Button button = (source as GameObject).GetComponent<Button>();
            if(button.isNotNull())
                button.onClick.RemoveAllListeners();
        }
    }

    void LinkButton()
    {
        Button button = (source as GameObject).GetComponent<Button>(); ; 
        button.onClick.AddListener(() => Invoke());
    }

    void LinkNavigation(ControlBehaviour controlBehaviour)
    {
        if (destination is ControlBehaviour)
        {
            Button button = (source as GameObject).GetComponent<Button>(); ;
            ControlBehaviour toScreen = destination as ControlBehaviour, currentScreen = controlBehaviour;
            button.onClick.AddListener(() => currentScreen.NavigateTo(toScreen));
        }
    }


    void Invoke()
    {
        object[] paramts = parameters.Select(p => p.value).ToArray();
        destination.InvokeMethod(methodPath, paramts);
    }
}


[Serializable]
public class Parameter
{
    public UnityEngine.Object source;
    public string memberPath, type, name;

    object o_source = null;

    object Source { get { return (source == null) ? o_source : source; } }

    public void SetObject(object obj) { o_source = obj; }

    public object value
    {
        get { return Source.GetValue(memberPath); }
    }

    public static object[] GetParameters(List<Parameter> parameter)
    {
        return parameter.Select(p => p.value).ToArray();
    }
}
